package org.codetranslators.compiler.tiger;

import java.util.Vector;

import org.codetranslators.compiler.abstractassembly.*;
import org.codetranslators.compiler.canon.AssemStmListList;

public class Debug {
	
	private void indent(int d) 
	{
      for(int i = 0; i <d ; i++) 
            System.out.print(' ');
	}
	
	private void printLn(String s)
	{
		System.out.println(s);
	}
	
	private void print(String s)
	{
		System.out.print(s);
	}
	
	public void printAssem(AssemType assemType)
	{
		if(assemType instanceof AssemStm)
			print((AssemStm)assemType);
		else
			print((AssemExp)assemType);
	}
	
	public void print(AssemStm stm) 
	{
		printStm(stm, 0);
		print("\n");
	}
	
	public void print(AssemExp e) {printExp(e,0); print("\n");}
	
	private void printStm(AssemStm s, int d) 
	{
		//if (s instanceof MipsAssemTypeList) printStm((MipsAssemTypeList)s, d);
		if (s instanceof AssemSeq) printStm((AssemSeq)s, d);
	    else if (s instanceof AssemLabel) printStm((AssemLabel)s, d);
	    else if (s instanceof AssemJump) printStm((AssemJump)s, d);
	    else if (s instanceof AssemCJump) printStm((AssemCJump)s, d);
	    else if (s instanceof AssemMove) printStm((AssemMove)s, d);
	    else if (s instanceof AssemExpStm) printStm((AssemExpStm)s, d);
    }
	
	private void printExp(AssemExp e, int d) {
       if (e instanceof AssemBinOpExp) printExp((AssemBinOpExp)e, d);
	   else if (e instanceof AssemMemory) printExp((AssemMemory)e, d);
	   else if (e instanceof AssemTemp) printExp((AssemTemp)e, d);
	   else if (e instanceof AssemSeqExp) printExp((AssemSeqExp)e, d);
	   else if (e instanceof AssemName) printExp((AssemName)e, d);
	   else if (e instanceof AssemConst) printExp((AssemConst)e, d);
	   else if (e instanceof AssemCallExp) printExp((AssemCallExp)e, d);
  }
	/*
	private void printStm(MipsAssemTypeList s, int d)
	{
		indent(d); printLn(s.getDescription() + "(");
		AssemType head = s.getFirstAssemType();
		if(head instanceof MipsAssemStm)
			printStm((MipsAssemStm)head,d+4); 
		else
			printExp((MipsAssemExp)head,d+4); 
		printLn(",");
		if(s.getTail() != null)
			printStm(s.getTail(),d+4); print(")");
	}
	*/
	private void printStm(AssemSeq s, int d)
	{
		indent(d); printLn(s.getDescription() + "("); printStm(s.getLeftStm(),d+4); printLn(",");
		printStm(s.getRightStm(),d+4); print(")");
	}
	
	private void printStm(AssemLabel s, int d)
	{
	      indent(d); print("LABEL "); print(s.getDescription());
	}

	private void printStm(AssemJump s, int d) 
	{
	      indent(d); printLn("JUMP("); printExp(s.getLabelExp(), d+4); print(")");
	}
	
	private void printStm(AssemCJump s, int d) {
	      indent(d); print("CJUMP("); 
	      switch(s.relop) {
	        case AssemCJump.EQ: print("EQ"); break;
	        case AssemCJump.NE: print("NE"); break;
	        case AssemCJump.LT: print("LT"); break;
	        case AssemCJump.GT: print("GT"); break;
	        case AssemCJump.LE: print("LE"); break;
	        case AssemCJump.GE: print("GE"); break;
	        case AssemCJump.ULT: print("ULT"); break;
	        case AssemCJump.ULE: print("ULE"); break;
	        case AssemCJump.UGT: print("UGT"); break;
	        case AssemCJump.UGE: print("UGE"); break;
	      }
	        printLn(","); printExp(s.getLeft(),d+4); printLn(",");
	        printExp(s.getRight(),d+4); printLn(",");
	       indent(d+4); print(s.getIfTrueLabel().toString()); print(","); 
	       print(s.getIfFalseLabel().toString()); 
	       print(")");
	  }
	
	private void printStm(AssemMove moveStm, int indentSpace)
	{
		indent(indentSpace);
		printLn(moveStm.getDescription());
		printExp(moveStm.getDst(), indentSpace + 4);
		printLn(",");
		printExp(moveStm.getSrc(), indentSpace + 4);
		print(")");
	}
	
	private void printStm(AssemExpStm expStm, int identSpace)
	{
		indent(identSpace); printLn("EXP("); 
		printExp(expStm.getExp(),identSpace+4); print(")"); 
	}
	
	private void printExp(AssemBinOpExp e, int d) {
	     indent(d); print("MipsAssemBinOp("); 
	      switch(e.getOperator()) {
		case AssemBinOpExp.PLUS: print("PLUS"); break;
		case AssemBinOpExp.MINUS: print("MINUS"); break;
		case AssemBinOpExp.MUL: print("MUL"); break;
		case AssemBinOpExp.DIV: print("DIV"); break;
		case AssemBinOpExp.AND: print("AND"); break;
		case AssemBinOpExp.OR: print("OR"); break;
		case AssemBinOpExp.LSHIFT: print("LSHIFT"); break;
		case AssemBinOpExp.RSHIFT: print("RSHIFT"); break;
		case AssemBinOpExp.ARSHIFT: print("ARSHIFT"); break;
		case AssemBinOpExp.XOR: print("XOR"); break;
		default:
	         throw new Error("Print.printExp.MipsAssemBinOp");
	       }
	      printLn(",");
	      printExp(e.getLeft(),d+4); printLn(","); printExp(e.getRight(),d+4); print(")");
	   }

	private void printExp(AssemMemory e, int d) {
	     indent(d);
		printLn("MEM("); printExp(e.getMemExp(),d+4); print(")");
	  }

	private void printExp(AssemTemp e, int d) {
	     indent(d); print(e.getDescription()); 
	     //print(e.getDescription());
	  }

	private void printExp(AssemSeqExp e, int d) {
	     indent(d); printLn("ESEQ("); printStm(e.getStm(),d+4); printLn(",");
		printExp(e.getExp(),d+4); print(")");

	  }

	private void printExp(AssemName e, int d) {
	     indent(d); print("NAME "); print(e.getDescription());
	  }

	private void printExp(AssemConst e, int d) {
	     indent(d); print("CONST "); print("" + e.getValue());
	  }

	private void printExp(AssemCallExp e, int d) {
	     indent(d); printLn("CALL(");
		printExp(e.getFunction(),d+4);
	        for(AssemExpList a = e.getArgs(); a!=null; a=a.getTail()) {
	           printLn(","); printExp(a.getHead(),d+2); 
	        }
	        print(")");
	  }
	
	public void print(AssemStmList stms)
	{
		for(AssemStmList l = stms; l != null; l = l.getStmList())
			print(l.getStm());
	}
	
	public void print(AssemStmListList bb)
	{
		int count = 1;
		for(AssemStmListList l = bb; l!=null; l=l.getTail()) 
		{
		       printLn("******************Basic Block " + count);
		       print(l.getHead());
		       printLn("******************End Basic Block " + count);
		       printLn("");
		       count++;
		} 
	}
	
	public void print(Vector basicBlocks)
	{
		int num = basicBlocks.size();
		for(int i = 0; i < num; i++)
		{
			printLn("******************Basic Block " + (i + 1));
			print((AssemStmList)basicBlocks.elementAt(i));
			printLn("******************End Basic Block " + (i + 1));
		}
	}
}
